home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / interp / fd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-18  |  12.7 KB  |  468 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: fd.c,v 1.18 94/07/26 18:32:28 hallgren Exp $
  27. *
  28. * This file implements an interface to file descriptors.
  29. *
  30. \**********************************************************************/
  31.  
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <sys/types.h>
  35. #include <sys/time.h>
  36. #include <errno.h>
  37. #include <sys/file.h>
  38. #ifdef MACH
  39. #define alloca buttplug1
  40. #define pause buttplug2
  41. #define execvp buttplug3
  42. #include <libc.h>
  43. #undef alloca
  44. #undef pause
  45. #undef execvp
  46. extern int execvp(const char *, char *const []);
  47. #endif MACH
  48. #ifdef hpux
  49. #include <stdlib.h>
  50. #define pause buttplug
  51. #include <unistd.h>
  52. #undef pause
  53. #include <fcntl.h>
  54. /* hpux doesn't define these for some reason. */
  55. extern int sys_nerr;
  56. extern char *sys_errlist[];
  57. #endif hpux
  58. #if defined(__osf__) || defined(ultrix)
  59. #include <stdlib.h>
  60. #define pause buttplug
  61. #include <unistd.h>
  62. #undef pause
  63. #include <fcntl.h>
  64. extern void bzero(char *string, int length);
  65. extern int select(int nfds, fd_set *readfds, fd_set *writefds,
  66.           fd_set *exceptfds, struct timeval *timeout);
  67. extern int fsync(int filedes);
  68. #endif
  69. #ifdef sgi
  70. #define pause buttplug
  71. #include <unistd.h>
  72. #undef pause
  73. #include <sys/stat.h>
  74. #include <fcntl.h>
  75. #include <bstring.h>
  76. #include <stdlib.h>
  77. #endif sgi
  78. #ifdef ultrix
  79. extern int sys_nerr;
  80. extern char *sys_errlist[];
  81. #endif ultrix
  82. #ifdef linux
  83. #define pause buttplug
  84. #include <unistd.h>
  85. #undef pause
  86. #endif
  87. #ifdef sparc
  88. #define pause buttplug
  89. #include <unistd.h>
  90. #undef pause
  91. extern void bzero(char *string, int length);
  92. extern int select(int nfds, fd_set *readfds, fd_set *writefds,
  93.           fd_set *exceptfds, struct timeval *timeout);
  94. extern int sys_nerr;
  95. extern char *sys_errlist[];
  96. #include <malloc.h>
  97. #include <fcntl.h>
  98. #endif
  99.  
  100. #include "mindy.h"
  101. #include "list.h"
  102. #include "bool.h"
  103. #include "thread.h"
  104. #include "func.h"
  105. #include "driver.h"
  106. #include "buf.h"
  107. #include "str.h"
  108. #include "num.h"
  109. #include "obj.h"
  110. #include "def.h"
  111.  
  112. static void results(struct thread *thread, obj_t *old_sp,
  113.             int okay, obj_t result)
  114. {
  115.     thread->sp = old_sp + 2;
  116.  
  117.     if (okay < 0) {
  118.     old_sp[0] = obj_False;
  119.     old_sp[1] = make_fixnum(errno);
  120.     }
  121.     else {
  122.     old_sp[0] = result;
  123.     old_sp[1] = obj_False;
  124.     }
  125.  
  126.     do_return(thread, old_sp, old_sp);
  127. }
  128.  
  129. static void fd_close(obj_t self, struct thread *thread, obj_t *args)
  130. {
  131.     obj_t fd = args[0];
  132.  
  133.     results(thread, args-1, close(fixnum_value(fd)), obj_True);
  134. }
  135.  
  136. static obj_t fd_error_str(obj_t errno)
  137. {
  138.     if (fixnum_value(errno) < 0 || fixnum_value(errno) >= sys_nerr)
  139.     return obj_False;
  140.     else
  141.     return make_string(sys_errlist[fixnum_value(errno)]);
  142. }
  143.  
  144. static int input_available(int fd)
  145. {
  146.     fd_set fds;
  147.     struct timeval tv;
  148.  
  149.     FD_ZERO(&fds);
  150.     FD_SET(fd, &fds);
  151.     tv.tv_sec = 0;
  152.     tv.tv_usec = 0;
  153. #ifdef hpux
  154.     return select(fd+1, (int *)&fds, NULL, NULL, &tv);
  155. #else
  156.     return select(fd+1, &fds, NULL, NULL, &tv);
  157. #endif
  158. }
  159.  
  160. static void fd_input_available(obj_t self, struct thread *thread, obj_t *args)
  161. {
  162.     int fd = fixnum_value(args[0]);
  163.     int res = input_available(fd);
  164.  
  165.     results(thread, args-1, res, res ? obj_True : obj_False);
  166. }
  167.  
  168. static void fd_open(obj_t self, struct thread *thread, obj_t *args)
  169. {
  170.     obj_t path = args[0];
  171.     obj_t flags = args[1];
  172.     int res;
  173.  
  174.     res = open(string_chars(path), fixnum_value(flags), 0666);
  175.  
  176.     results(thread, args-1, res, make_fixnum(res));
  177. }
  178.  
  179. static void maybe_read(struct thread *thread)
  180. {
  181.     obj_t *fp = thread->fp;
  182.     int fd = fixnum_value(fp[-8]);
  183.     int nfound, res;
  184.     obj_t *old_sp;
  185.  
  186.     nfound = input_available(fd);
  187.     if (nfound < 0) {
  188.     old_sp = pop_linkage(thread);
  189.     thread->sp = old_sp + 2;
  190.     old_sp[0] = obj_False;
  191.     old_sp[1] = make_fixnum(errno);
  192.     do_return(thread, old_sp, old_sp);
  193.     }
  194.     else if (nfound == 0)
  195.     wait_for_input(thread, fd, maybe_read);
  196.     else {
  197.     res = read(fd,
  198.            buffer_data(fp[-7]) + fixnum_value(fp[-6]),
  199.            fixnum_value(fp[-5]));
  200.     
  201.     results(thread, pop_linkage(thread), res, make_fixnum(res));
  202.     }
  203. }
  204.  
  205. static void fd_read(obj_t self, struct thread *thread, obj_t *args)
  206. {
  207.     thread->sp = args + 4;
  208.     push_linkage(thread, args);
  209.     maybe_read(thread);
  210. }
  211.  
  212. static void fd_seek(obj_t self, struct thread *thread, obj_t *args)
  213. {
  214.     obj_t fd = args[0];
  215.     obj_t offset = args[1];
  216.     obj_t whence = args[2];
  217.     off_t res;
  218.  
  219.     res = lseek(fixnum_value(fd), fixnum_value(offset), fixnum_value(whence));
  220.  
  221.     results(thread, args-1, res, make_fixnum(res));
  222. }
  223.  
  224. static void fd_sync_output(obj_t self, struct thread *thread, obj_t *args)
  225. {
  226.     int res = fsync(fixnum_value(args[0]));
  227.  
  228.     if (res < 0 && errno == EINVAL)
  229.     /* EINVAL means the fd is a socket, not a file descriptor.  We don't */
  230.     /* care that you can't fsync sockets. */
  231.     results(thread, args-1, 0, obj_True);
  232.     else
  233.     results(thread, args-1, res, obj_True);
  234. }
  235.  
  236. static void maybe_write(struct thread *thread)
  237. {
  238.     obj_t *fp = thread->fp;
  239.     int fd = fixnum_value(fp[-8]);
  240.     fd_set fds;
  241.     struct timeval tv;
  242.     int nfound, res;
  243.     obj_t *old_sp;
  244.  
  245.     FD_ZERO(&fds);
  246.     FD_SET(fd, &fds);
  247.     tv.tv_sec = 0;
  248.     tv.tv_usec = 0;
  249. #ifdef hpux
  250.     nfound = select(fd+1, NULL, (int *)&fds, NULL, &tv);
  251. #else
  252.     nfound = select(fd+1, NULL, &fds, NULL, &tv);
  253. #endif
  254.  
  255.     if (nfound < 0)
  256.     if (errno != EINTR) {
  257.         old_sp = pop_linkage(thread);
  258.         thread->sp = old_sp + 2;
  259.         old_sp[0] = obj_False;
  260.         old_sp[1] = make_fixnum(errno);
  261.         do_return(thread, old_sp, old_sp);
  262.     }
  263.     else
  264.         wait_for_output(thread, fd, maybe_write);
  265.     else if (nfound == 0)
  266.     wait_for_output(thread, fd, maybe_write);
  267.     else {
  268.     res = write(fd,
  269.             buffer_data(fp[-7]) + fixnum_value(fp[-6]),
  270.             fixnum_value(fp[-5]));
  271.  
  272.     results(thread, pop_linkage(thread), res, make_fixnum(res));
  273.     }
  274. }
  275.  
  276. static void fd_write(obj_t self, struct thread *thread, obj_t *args)
  277. {
  278.     thread->sp = args + 4;
  279.     push_linkage(thread, args);
  280.     maybe_write(thread);
  281. }
  282.  
  283.  
  284. /* Function to run an arbitrary program, returning file descriptors for the
  285.    program's stdin and stdout. */
  286. static void fd_exec(obj_t self, struct thread *thread, obj_t *args)
  287. {
  288.     int inpipes[2], outpipes[2], forkresult;
  289.     obj_t *oldargs;
  290.  
  291.     oldargs = args - 1;
  292.     thread->sp = args + 1;
  293.  
  294.     if (pipe(inpipes) >= 0 && pipe(outpipes) >= 0 &&
  295.     (forkresult = fork()) != -1)
  296.     {
  297.     if (forkresult == 0) {
  298.         /* This process is going to exit shortly, so we needn't be too
  299.            careful about malloc behavior, nor about the fact that we
  300.            destructively modify the command string. */
  301.         char *command = string_chars(args[0]);
  302.         char *p, **args;
  303.         int argcounter = 1;
  304.  
  305.         for (p = command; *p != 0; p++)
  306.         if (*p == ' ') {
  307.             argcounter++;
  308.             while (*(++p) == ' ');
  309.         }
  310.         args = (char **) calloc(argcounter+1, sizeof(char *));
  311.         args[0] = command;
  312.         for (p = command, argcounter = 1; *p != 0; p++) {
  313.         if (*p == ' ') {
  314.             *p = 0;
  315.             while (*(++p) == ' ');
  316.             if (*p != 0)
  317.             args[argcounter++] = p;
  318.         }
  319.         }
  320.         args[argcounter] = 0;
  321.  
  322.         close(0);
  323.         dup(inpipes[0]);
  324.         close(inpipes[0]);
  325.         close(inpipes[1]);
  326.         close(1);
  327.         dup(outpipes[1]);
  328.         close(outpipes[0]);
  329.         close(outpipes[1]);
  330.         execvp(args[0], args);
  331.         /* We never get here.... */
  332.     }
  333.     close(inpipes[0]);
  334.     close(outpipes[1]);
  335.     
  336.     oldargs[0] = make_fixnum(inpipes[1]);
  337.     oldargs[1] = make_fixnum(outpipes[0]);
  338.     } else {
  339.     oldargs[0] = obj_False;
  340.     oldargs[1] = obj_False;
  341.     }
  342.  
  343.     do_return(thread, oldargs, oldargs);
  344. }
  345.  
  346.  
  347. /* Init stuff. */
  348.  
  349. void init_fd_functions(void)
  350. {
  351.     define_constant("fd-close",
  352.             make_raw_method("fd-close", list1(obj_IntegerClass),
  353.                     FALSE, obj_False, FALSE,
  354.                     list2(obj_BooleanClass, obj_ObjectClass),
  355.                     obj_False, fd_close));
  356.     define_method("fd-error-string", list1(obj_IntegerClass), FALSE, obj_False,
  357.           FALSE, obj_ObjectClass, fd_error_str);
  358.     define_constant("fd-input-available?",
  359.             make_raw_method("fd-input-available?",
  360.                     list1(obj_IntegerClass),
  361.                     FALSE, obj_False, FALSE,
  362.                     list2(obj_BooleanClass, obj_ObjectClass),
  363.                     obj_False, fd_input_available));
  364.     define_constant("fd-open",
  365.             make_raw_method("fd-open",
  366.                     list2(obj_ByteStringClass,
  367.                       obj_IntegerClass),
  368.                     FALSE, obj_False, FALSE,
  369.                     list2(obj_ObjectClass, obj_ObjectClass),
  370.                     obj_False, fd_open));
  371.     define_constant("fd-read",
  372.             make_raw_method("fd-read",
  373.                     listn(4, obj_IntegerClass, obj_BufferClass,
  374.                       obj_IntegerClass, obj_IntegerClass),
  375.                     FALSE, obj_False, FALSE,
  376.                     list2(obj_ObjectClass, obj_ObjectClass),
  377.                     obj_False, fd_read));
  378.     define_constant("fd-seek",
  379.             make_raw_method("fd-seek",
  380.                     list3(obj_IntegerClass, obj_IntegerClass,
  381.                       obj_IntegerClass),
  382.                     FALSE, obj_False, FALSE,
  383.                     list2(obj_ObjectClass, obj_ObjectClass),
  384.                     obj_False, fd_seek));
  385.     define_constant("fd-sync-output",
  386.             make_raw_method("fd-sync-output",
  387.                     list1(obj_IntegerClass),
  388.                     FALSE, obj_False, FALSE,
  389.                     list2(obj_BooleanClass, obj_ObjectClass),
  390.                     obj_False, fd_sync_output));
  391.     define_constant("fd-write",
  392.             make_raw_method("fd-write",
  393.                     listn(4, obj_IntegerClass, obj_BufferClass,
  394.                       obj_IntegerClass, obj_IntegerClass),
  395.                     FALSE, obj_False, FALSE,
  396.                     list2(obj_ObjectClass, obj_ObjectClass),
  397.                     obj_False, fd_write));
  398.     define_constant("fd-exec",
  399.             make_raw_method("fd-exec",
  400.                     list1(obj_ByteStringClass),
  401.                     FALSE, obj_False, FALSE,
  402.                     list2(obj_ObjectClass, obj_ObjectClass),
  403.                     obj_False, fd_exec));
  404.  
  405.     define_constant("L_SET", make_fixnum(L_SET));
  406.     define_constant("L_INCR", make_fixnum(L_INCR));
  407.     define_constant("L_XTND", make_fixnum(L_XTND));
  408.  
  409.     define_constant("FNDELAY", make_fixnum(FNDELAY));
  410. #ifdef FAPPEND
  411.     define_constant("FAPPEND", make_fixnum(FAPPEND));
  412. #else
  413.     define_constant("FAPPEND", make_fixnum(O_APPEND));
  414. #endif
  415.  
  416. #ifdef FCREAT
  417.     define_constant("FCREAT", make_fixnum(FCREAT));
  418. #else
  419.     define_constant("FCREAT", make_fixnum(O_CREAT));
  420. #endif
  421. #ifdef FTRUNC
  422.     define_constant("FTRUNC", make_fixnum(FTRUNC));
  423. #else
  424.     define_constant("FTRUNC", make_fixnum(O_TRUNC));
  425. #endif
  426. #ifdef FEXCL
  427.     define_constant("FEXCL", make_fixnum(FEXCL));
  428. #else
  429.     define_constant("FEXCL", make_fixnum(O_EXCL));
  430. #endif
  431.  
  432.     define_constant("O_RDONLY", make_fixnum(O_RDONLY));
  433.     define_constant("O_WRONLY", make_fixnum(O_WRONLY));
  434.     define_constant("O_RDWR", make_fixnum(O_RDWR));
  435.     define_constant("O_NDELAY", make_fixnum(O_NDELAY));
  436.     define_constant("O_APPEND", make_fixnum(O_APPEND));
  437.     define_constant("O_CREAT", make_fixnum(O_CREAT));
  438.     define_constant("O_TRUNC", make_fixnum(O_TRUNC));
  439.     define_constant("O_EXCL", make_fixnum(O_EXCL));
  440.  
  441.     define_constant("ENOENT", make_fixnum(ENOENT));
  442.     define_constant("EIO", make_fixnum(EIO));
  443.     define_constant("ENXIO", make_fixnum(ENXIO));
  444.     define_constant("EACCES", make_fixnum(EACCES));
  445.     define_constant("EFAULT", make_fixnum(EFAULT));
  446.     define_constant("EEXIST", make_fixnum(EEXIST));
  447.     define_constant("ENOTDIR", make_fixnum(ENOTDIR));
  448.     define_constant("EISDIR", make_fixnum(EISDIR));
  449.     define_constant("EINVAL", make_fixnum(EINVAL));
  450.     define_constant("ENFILE", make_fixnum(ENFILE));
  451.     define_constant("EMFILE", make_fixnum(EMFILE));
  452.     define_constant("ETXTBSY", make_fixnum(ETXTBSY));
  453.     define_constant("ENOSPC", make_fixnum(ENOSPC));
  454.     define_constant("EROFS", make_fixnum(EROFS));
  455.     define_constant("EOPNOTSUPP", make_fixnum(EOPNOTSUPP));
  456.     define_constant("ELOOP", make_fixnum(ELOOP));
  457.     define_constant("ENAMETOOLONG", make_fixnum(ENAMETOOLONG));
  458.     define_constant("EDQUOT", make_fixnum(EDQUOT));
  459.  
  460.     define_constant("EBADF", make_fixnum(EBADF));
  461.  
  462.     define_constant("EINTR", make_fixnum(EINTR));
  463.     define_constant("EWOULDBLOCK", make_fixnum(EWOULDBLOCK));
  464.  
  465.     define_constant("EPIPE", make_fixnum(EPIPE));
  466.     define_constant("EFBIG", make_fixnum(EFBIG));
  467. }
  468.